import java.util.concurrent.atomic.AtomicInteger;

public final class fannkuchredux implements Runnable {
	private static final int MAX_N = 32;
	private static final int NCHUNKS = 360;
	private static final AtomicInteger taskId = new AtomicInteger(0);
	private static final fannkuchredux instance = new fannkuchredux();
	private static int CHUNKSZ;
	private static int NTASKS;
	private static int N;
	private static int[] fact;
	private static int[] maxFlips;
	private static int[] checkSums;

	@Override
	public void run() {
		var CHUNKSZ = fannkuchredux.CHUNKSZ;
		var NTASKS = fannkuchredux.NTASKS;
		var N = fannkuchredux.N;
		var fact = fannkuchredux.fact;
		var maxFlips = fannkuchredux.maxFlips;
		var checkSums = fannkuchredux.checkSums;
		var p = new int[MAX_N];
		var pp = new int[MAX_N];
		var count = new int[MAX_N];
		for (int task; (task = taskId.getAndIncrement()) < NTASKS; ) {
			int idxMin = task * CHUNKSZ;
			int idxMax = Math.min(fact[N], idxMin + CHUNKSZ);

			for (int i = 0; i < N; i++)
				p[i] = i;
			for (int i = N, idx = idxMin; --i > 0; ) {
				int d = idx / fact[i];
				count[i] = d;
				idx = idx % fact[i];
				System.arraycopy(p, 0, pp, 0, N); // i + 1
				for (int j = 0; j <= i; j++)
					p[j] = j + d <= i ? pp[j + d] : pp[j + d - i - 1];
			}

			int maxflips = 1;
			int chksum = 0;
			var sign = true;
			for (int i = idxMin; ; sign = !sign) {
				int first = p[0];
				if (first != 0) {
					int flips = 1;
					if (p[first] != 0) {
						System.arraycopy(p, 0, pp, 0, N);
						int p0 = first;
						do {
							flips++;
							for (int lo = 1, hi = p0 - 1; lo < hi; lo++, hi--) {
								int t = pp[lo];
								pp[lo] = pp[hi];
								pp[hi] = t;
							}
							int t = pp[p0];
							pp[p0] = p0;
							p0 = t;
						} while (pp[p0] != 0);
					}
					if (maxflips < flips)
						maxflips = flips;
					if (sign)
						chksum += flips;
					else
						chksum -= flips;
				}
				if (++i == idxMax)
					break;

				// nextPermutation
				if (sign) {
					p[0] = p[1];
					p[1] = first;
				} else {
					int t = p[1];
					p[1] = p[2];
					p[2] = t;
					for (int k = 2; ++count[k] > k; k++) {
						count[k] = 0;
						for (int j = 0; j <= k; j++)
							p[j] = p[j + 1];
						p[k + 1] = first;
						first = p[0];
					}
				}
			}
			maxFlips[task] = maxflips;
			checkSums[task] = chksum;
		}
	}

	static void printResult(int n, int res, int chk) {
		System.out.println(chk + "\nPfannkuchen(" + n + ") = " + res);
	}

	public static void main(String[] args) throws Exception {
		N = args.length > 0 ? Integer.parseInt(args[0]) : 12;
		if (N < 0 || N > 12) {
			printResult(N, -1, -1);
			return;
		}
		if (N <= 1) {
			printResult(N, 0, 0);
			return;
		}

		//noinspection NonStrictComparisonCanBeEquality
		for (int TEST_COUNT = 1; --TEST_COUNT >= 0; taskId.set(0)) {
			// var timeBegin = System.nanoTime();
			fact = new int[N + 1];
			fact[0] = 1;
			for (int i = 1; i < fact.length; i++)
				fact[i] = fact[i - 1] * i;

			CHUNKSZ = (fact[N] + NCHUNKS - 1) / NCHUNKS;
			NTASKS = (fact[N] + CHUNKSZ - 1) / CHUNKSZ;
			System.out.println(NTASKS);
			maxFlips = new int[NTASKS];
			checkSums = new int[NTASKS];

			int nthreads = Runtime.getRuntime().availableProcessors();
			var threads = new Thread[nthreads];
			for (int i = 0; i < nthreads; i++)
				(threads[i] = new Thread(fannkuchredux.instance)).start();
			for (var t : threads)
				t.join();

			int res = 0;
			for (int v : maxFlips)
				res = Math.max(res, v);
			int chk = 0;
			for (int v : checkSums)
				chk += v;
			printResult(N, res, chk);
			// System.out.println((System.nanoTime() - timeBegin) / 1_000_000 + " ms");
		}
	}
}
